home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 April / enter-2004-04.iso / files / httrack-3.30.exe / {app} / src / htscache.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-10-11  |  32.2 KB  |  984 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       cache system (index and stores files in cache)         */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. #include "htscache.h"
  39.  
  40. /* specific definitions */
  41. #include "htsbase.h"
  42. #include "htsbasenet.h"
  43. #include "htsmd5.h"
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47.  
  48. #include "htsnostatic.h"
  49. /* END specific definitions */
  50.  
  51. #undef test_flush
  52. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  53.  
  54. // routines de mise en cache
  55.  
  56. /*
  57.   VERSION 1.0 :
  58.   -----------
  59.  
  60. .ndx file
  61.  file with data
  62.    <string>(date/time) [ <string>(hostname+filename) (datfile_position_ascii) ] * number_of_links
  63.  file without data
  64.    <string>(date/time) [ <string>(hostname+filename) (-datfile_position_ascii) ] * number_of_links
  65.  
  66. .dat file
  67.  [ file ] * 
  68. with
  69.   file= (with data)
  70.    [ bytes ] * sizeof(htsblk header) [ bytes ] * n(length of file given in htsblk header)
  71.  file= (without data)
  72.    [ bytes ] * sizeof(htsblk header)
  73. with
  74.  <string>(name) = <length in ascii>+<lf>+<data>
  75.  
  76.  
  77.   VERSION 1.1/1.2 :
  78.   ---------------
  79.  
  80. .ndx file
  81.  file with data
  82.    <string>("CACHE-1.1") <string>(date/time) [ <string>(hostname+filename) (datfile_position_ascii) ] * number_of_links
  83.  file without data
  84.    <string>("CACHE-1.1") <string>(date/time) [ <string>(hostname+filename) (-datfile_position_ascii) ] * number_of_links
  85.  
  86. .dat file
  87.    <string>("CACHE-1.1") [ [Header_1.1] [bytes] * n(length of file given in header) ] *
  88. with
  89.  Header_1.1=
  90.    <int>(statuscode)
  91.    <int>(size)
  92.    <string>(msg)
  93.    <string>(contenttype)
  94.    <string>(charset) [version 3]
  95.    <string>(last-modified)
  96.    <string>(Etag)
  97.    <string>location
  98.    <string>Content-disposition [version 2]
  99.    <string>hostname [version 4]
  100.    <string>URI filename [version 4]
  101.    <string>local filename [version 4]
  102.    [<string>"SD" <string>(supplemental data)]
  103.    [<string>"SD" <string>(supplemental data)]
  104.    ...
  105.    <string>"HTS" (end of header)
  106.    <int>(number of bytes of data) (0 if no data written)
  107. */
  108.  
  109. // Nouveau: si != text/html ne stocke que la taille
  110.  
  111.  
  112. void cache_mayadd(httrackp* opt,cache_back* cache,htsblk* r,char* url_adr,char* url_fil,char* url_save) {
  113.   if ((opt->debug>0) && (opt->log!=NULL)) {
  114.     fspc(opt->log,"debug"); fprintf(opt->log,"File checked by cache: %s"LF,url_adr);
  115.   }            
  116.   // ---stockage en cache---
  117.   // stocker dans le cache?
  118.   if (opt->cache) {
  119.     if (cache->dat!=NULL) {
  120.       // c'est le seul endroit ou l'on ajoute des elements dans le cache (fichier entier ou header)
  121.       // on stocke tout fichier "ok", mais Θgalement les rΘponses 404,301,302...
  122.       if ((r->statuscode==200)         /* stocker rΘponse standard, plus */
  123.         || (r->statuscode==204)     /* no content */
  124.         || (r->statuscode==301)     /* moved perm */
  125.         || (r->statuscode==302)     /* moved temp */
  126.         || (r->statuscode==303)     /* moved temp */
  127.         || (r->statuscode==307)     /* moved temp */
  128.         || (r->statuscode==401)     /* authorization */
  129.         || (r->statuscode==403)     /* unauthorized */
  130.         || (r->statuscode==404)     /* not found */
  131.         || (r->statuscode==410)     /* gone */
  132.         )
  133.       {        /* ne pas stocker si la page gΘnΘrΘe est une erreur */
  134.         if (!r->is_file) {
  135.           // stocker fichiers (et robots.txt)
  136.           if ( (strnotempty(url_save)) || (strcmp(url_fil,"/robots.txt")==0)) {
  137.             // ajouter le fichier au cache
  138.             cache_add(*r,url_adr,url_fil,url_save,cache->ndx,cache->dat,opt->all_in_cache);
  139.           }
  140.         }
  141.       }
  142.     }
  143.   }
  144.   // ---fin stockage en cache---
  145. }
  146.  
  147.  
  148. /* Ajout d'un fichier en cache */
  149. void cache_add(htsblk r,char* url_adr,char* url_fil,char* url_save,FILE* cache_ndx,FILE* cache_dat,int all_in_cache) {
  150.   int pos;
  151.   char s[256];
  152.   char buff[HTS_URLMAXSIZE*4];
  153.   int ok=1;
  154.   int dataincache=0;    // donnΘe en cache?
  155.   /*char digest[32+2];*/
  156.   /*digest[0]='\0';*/
  157.  
  158.   // Longueur url_save==0?
  159.   if ( (strnotempty(url_save)==0) ) {
  160.     if (strcmp(url_fil,"/robots.txt")==0)        // robots.txt
  161.       dataincache=1;
  162.     else
  163.       return;   // erreur (sauf robots.txt)
  164.   }
  165.  
  166.   if (r.size <= 0)   // taille <= 0 
  167.     return;          // refusΘ..
  168.  
  169.   // Mettre les *donΘes* en cache ?
  170.   if (is_hypertext_mime(r.contenttype))    // html, mise en cache des donnΘes et 
  171.     dataincache=1;                               // pas uniquement de l'en tΩte
  172.   else if (all_in_cache)
  173.     dataincache=1;                               // forcer tout en cache
  174.  
  175.   /* calcul md5 ? */
  176.   /*
  177.   if (is_hypertext_mime(r.contenttype)) {    // html, calcul MD5
  178.     if (r.adr) {
  179.       domd5mem(r.adr,r.size,digest,1);
  180.     }
  181.   }*/
  182.  
  183.   // Position
  184.   fflush(cache_dat); fflush(cache_ndx);
  185.   pos=ftell(cache_dat);
  186.   // Θcrire pointeur seek, adresse, fichier
  187.   if (dataincache)   // patcher
  188.     sprintf(s,"%d\n",pos);    // ecrire tel que (eh oui Θvite les \0..)
  189.   else
  190.     sprintf(s,"%d\n",-pos);   // ecrire tel que (eh oui Θvite les \0..)
  191.  
  192.   // data
  193.   // Θcrire donnΘes en-tΩte, donnΘes fichier
  194.   /*if (!dataincache) {   // patcher
  195.     r.size=-r.size;  // nΘgatif
  196.   }*/
  197.  
  198.   // Construction header
  199.   ok=0;
  200.   if (cache_wint(cache_dat,r.statuscode) != -1       // statuscode
  201.   && cache_wLLint(cache_dat,r.size) != -1           // size
  202.   && cache_wstr(cache_dat,r.msg) != -1              // msg
  203.   && cache_wstr(cache_dat,r.contenttype) != -1      // contenttype
  204.   && cache_wstr(cache_dat,r.charset) != -1          // contenttype
  205.   && cache_wstr(cache_dat,r.lastmodified) != -1     // last-modified
  206.   && cache_wstr(cache_dat,r.etag) != -1             // Etag
  207.   && cache_wstr(cache_dat,(r.location!=NULL)?r.location:"") != -1         // 'location' pour moved
  208.   && cache_wstr(cache_dat,r.cdispo) != -1           // Content-disposition
  209.   && cache_wstr(cache_dat,url_adr) != -1            // Original address
  210.   && cache_wstr(cache_dat,url_fil) != -1            // Original URI filename
  211.   && cache_wstr(cache_dat,url_save) != -1           // Original save filename
  212.   && cache_wstr(cache_dat,"HTS") != -1              // end of header
  213.   ) {
  214.     ok=1;       /* ok */
  215.   }
  216.   // Fin construction header
  217.  
  218.   /*if ((int) fwrite((char*) &r,1,sizeof(htsblk),cache_dat) == sizeof(htsblk)) {*/
  219.   if (ok) {
  220.     if (dataincache) {    // mise en cache?
  221.       if (!r.adr) {       /* taille nulle (parfois en cas de 301 */
  222.         if (cache_wLLint(cache_dat,0)==-1)          /* 0 bytes */
  223.           ok=0;
  224.       } else if (r.is_write==0) {  // en mΘmoire, recopie directe
  225.         if (cache_wLLint(cache_dat,r.size)!=-1) {
  226.           if (r.size>0) {   // taille>0
  227.             if (fwrite(r.adr,1,(INTsys)r.size,cache_dat)!=r.size)
  228.               ok=0;
  229.           } else    // taille=0, ne rien Θcrire
  230.             ok=0;
  231.         } else
  232.           ok=0;
  233.       } else {  // recopier fichier dans cache
  234.         FILE* fp;
  235.         // On recopie le fichier..
  236.         LLint file_size=fsize(fconv(url_save));
  237.         if (file_size>=0) {
  238.           if (cache_wLLint(cache_dat,file_size)!=-1) {
  239.             fp=fopen(fconv(url_save),"rb");
  240.             if (fp!=NULL) {
  241.               char buff[32768];
  242.               INTsys nl;
  243.               do {
  244.                 nl=fread(buff,1,32768,fp);
  245.                 if (nl>0) { 
  246.                   if ((INTsys)fwrite(buff,1,(INTsys)nl,cache_dat)!=nl) {  // erreur
  247.                     nl=-1;
  248.                     ok=0;
  249.                   }
  250.                 }
  251.               } while(nl>0);
  252.               fclose(fp);
  253.             } else ok=0;
  254.           } else ok=0;
  255.         } else ok=0;
  256.       }
  257.     } else {
  258.       if (cache_wLLint(cache_dat,0)==-1)          /* 0 bytes */
  259.         ok=0;
  260.     }
  261.   } else ok=0;
  262.   /*if (!dataincache) {   // dΘpatcher
  263.     r.size=-r.size;
  264.   }*/
  265.  
  266.   // index
  267.   // adresse+cr+fichier+cr
  268.   if (ok) {
  269.     buff[0]='\0'; strcatbuff(buff,url_adr); strcatbuff(buff,"\n"); strcatbuff(buff,url_fil); strcatbuff(buff,"\n");
  270.     cache_wstr(cache_ndx,buff);
  271.     fwrite(s,1,strlen(s),cache_ndx);
  272.   }  // si ok=0 on a peut Ωtre Θcrit des donnΘes pour rien mais on s'en tape
  273.   
  274.   // en cas de plantage, on aura au moins le cache!
  275.   fflush(cache_dat); fflush(cache_ndx);
  276. }
  277.  
  278.  
  279. htsblk cache_read(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location) {
  280.   return cache_readex(opt,cache,adr,fil,save,location,NULL,0);
  281. }
  282.  
  283. htsblk cache_read_ro(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location) {
  284.   return cache_readex(opt,cache,adr,fil,save,location,NULL,1);
  285. }
  286.  
  287. // lecture d'un fichier dans le cache
  288. // si save==null alors test unqiquement
  289. htsblk cache_readex(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location,
  290.                     char* return_save, int readonly) {
  291. #if HTS_FAST_CACHE
  292.   long int hash_pos;
  293.   int hash_pos_return;
  294. #else
  295.   char* a;
  296. #endif
  297.   char buff[HTS_URLMAXSIZE*2];
  298.   char location_default[HTS_URLMAXSIZE*2];
  299.   char previous_save[HTS_URLMAXSIZE*2];
  300.   htsblk r;
  301.   int ok=0;
  302.   int header_only=0;
  303.  
  304.   memset(&r, 0, sizeof(htsblk)); r.soc=INVALID_SOCKET;
  305.   if (location) {
  306.     r.location = location;
  307.   } else {
  308.     r.location = location_default;
  309.   }
  310.   strcpybuff(r.location, ""); 
  311. #if HTS_FAST_CACHE
  312.   strcpybuff(buff,adr); strcatbuff(buff,fil);
  313.   hash_pos_return=inthash_read((inthash)cache->hashtable,buff,(long int*)&hash_pos);
  314. #else
  315.   buff[0]='\0'; strcatbuff(buff,"\n"); strcatbuff(buff,adr); strcatbuff(buff,"\n"); strcatbuff(buff,fil); strcatbuff(buff,"\n");
  316.   if (cache->use)
  317.     a=strstr(cache->use,buff);
  318.   else
  319.     a=NULL;       // forcer erreur
  320. #endif
  321.  
  322.   /* avoid errors on data entries */
  323.   if (adr[0] == '/' && adr[1] == '/' && adr[2] == '[') {
  324. #if HTS_FAST_CACHE
  325.     hash_pos_return = 0;
  326. #else
  327.     a = NULL;
  328. #endif
  329.   }
  330.  
  331.   // en cas de succΦs
  332. #if HTS_FAST_CACHE
  333.   if (hash_pos_return) {
  334. #else
  335.   if (a!=NULL) {  // OK existe en cache!
  336. #endif
  337.     INTsys pos;
  338. #if DEBUGCA
  339.     fprintf(stdout,"..cache: %s%s at ",adr,fil);
  340. #endif
  341.     
  342. #if HTS_FAST_CACHE
  343.     pos=hash_pos;     /* simply */
  344. #else
  345.     a+=strlen(buff);
  346.     sscanf(a,"%d",&pos);    // lire position
  347. #endif
  348. #if DEBUGCA
  349.     printf("%d\n",pos);
  350. #endif
  351.  
  352.     fflush(cache->olddat); 
  353.     if (fseek(cache->olddat,((pos>0)?pos:(-pos)),SEEK_SET) == 0) {
  354.       /* Importer cache1.0 */
  355.       if (cache->version==0) {
  356.         OLD_htsblk old_r;
  357.         if (fread((char*) &old_r,1,sizeof(old_r),cache->olddat)==sizeof(old_r)) { // lire tout (y compris statuscode etc)
  358.           r.statuscode=old_r.statuscode;
  359.           r.size=old_r.size;        // taille fichier
  360.           strcpybuff(r.msg,old_r.msg);
  361.           strcpybuff(r.contenttype,old_r.contenttype);
  362.           ok=1;     /* import  ok */
  363.         }
  364.       /* */
  365.       /* Cache 1.1 */
  366.       } else {
  367.         char check[256];
  368.         LLint size_read;
  369.         check[0]='\0';
  370.         //
  371.         cache_rint(cache->olddat,&r.statuscode);
  372.         cache_rLLint(cache->olddat,&r.size);
  373.         cache_rstr(cache->olddat,r.msg);
  374.         cache_rstr(cache->olddat,r.contenttype);
  375.         if (cache->version >= 3)
  376.           cache_rstr(cache->olddat,r.charset);
  377.         cache_rstr(cache->olddat,r.lastmodified);
  378.         cache_rstr(cache->olddat,r.etag);
  379.         cache_rstr(cache->olddat,r.location);
  380.         if (cache->version >= 2)
  381.           cache_rstr(cache->olddat,r.cdispo);
  382.         if (cache->version >= 4) {
  383.           cache_rstr(cache->olddat, previous_save);  // adr
  384.           cache_rstr(cache->olddat, previous_save);  // fil
  385.           previous_save[0] = '\0';
  386.           cache_rstr(cache->olddat, previous_save);  // save
  387.           if (return_save != NULL) {
  388.             strcpybuff(return_save, previous_save);
  389.           }
  390.         }
  391.         //
  392.         cache_rstr(cache->olddat,check);
  393.         if (strcmp(check,"HTS")==0) {           /* intΘgritΘ OK */
  394.           ok=1;
  395.         }
  396.         cache_rLLint(cache->olddat,&size_read);       /* lire size pour Ωtre s√r de la taille dΘclarΘe (rΘΘcrire) */
  397.         if (size_read>0) {                         /* si inscrite ici */
  398.           r.size=size_read;
  399.         } else {                              /* pas de donnΘes directement dans le cache, fichier prΘsent? */
  400.           if (r.statuscode!=200)
  401.             header_only=1;          /* que l'en tΩte ici! */
  402.         }
  403.       }
  404.  
  405.       /* Remplir certains champs */
  406.       r.totalsize=r.size;
  407.  
  408.       // lecture du header (y compris le statuscode)
  409.       /*if (fread((char*) &r,1,sizeof(htsblk),cache->olddat)==sizeof(htsblk)) { // lire tout (y compris statuscode etc)*/
  410.       if (ok) {
  411.         // sΘcuritΘ
  412.         r.adr=NULL;
  413.         r.out=NULL;
  414.         ////r.location=NULL;  non, fixΘe lors des 301 ou 302
  415.         r.fp=NULL;
  416.         
  417.         if ( (r.statuscode>=0) && (r.statuscode<=999)
  418.           && (r.notmodified>=0)  && (r.notmodified<=9) ) {   // petite vΘrif intΘgritΘ
  419.           if ((save) && (!header_only) ) {     /* ne pas lire uniquement header */
  420.             //int to_file=0;
  421.             
  422.             r.adr=NULL; r.soc=INVALID_SOCKET; 
  423.             // // r.location=NULL;
  424.             
  425. #if HTS_DIRECTDISK
  426.             // Court-circuit:
  427.             // Peut-on stocker le fichier directement sur disque?
  428.             if (!readonly && r.statuscode==200 && !is_hypertext_mime(r.contenttype) && strnotempty(save)) {    // pas HTML, Θcrire sur disk directement
  429.               int ok=0;
  430.               
  431.               r.is_write=1;    // Θcrire
  432.               if (fexist(fconv(save))) {  // un fichier existe dΘja
  433.                 //if (fsize(fconv(save))==r.size) {  // mΩme taille -- NON tant pis (taille mal declaree)
  434.                 ok=1;    // plus rien α faire
  435.                 filenote(save,NULL);        // noter comme connu
  436.                 //xxusercommand(opt,0,NULL,save,adr,fil);
  437.                 //}
  438.               }
  439.               
  440.               if ((pos<0) && (!ok)) { // Pas de donnΘe en cache et fichier introuvable : erreur!
  441.                 if (opt->norecatch) {
  442.                   filecreateempty(save);
  443.                   //
  444.                   r.statuscode=-1;
  445.                   strcpybuff(r.msg,"File deleted by user not recaught");
  446.                   ok=1;     // ne pas rΘcupΘrer (et pas d'erreur)
  447.                 } else {
  448.                   r.statuscode=-1;
  449.                   strcpybuff(r.msg,"Previous cache file not found");
  450.                   ok=1;    // ne pas rΘcupΘrer
  451.                 }
  452.               }
  453.               
  454.               if (!ok) {  
  455.                 r.out=filecreate(save);
  456. #if HDEBUG
  457.                 printf("direct-disk: %s\n",save);
  458. #endif
  459.                 if (r.out!=NULL) {
  460.                   char buff[32768+4];
  461.                   LLint size = r.size;
  462.                   if (size > 0) {
  463.                     INTsys nl;
  464.                     do {
  465.                       nl=fread(buff,1,(INTsys) minimum(size,32768),cache->olddat);
  466.                       if (nl>0) {
  467.                         size-=nl; 
  468.                         if ((INTsys)fwrite(buff,1,(INTsys)nl,r.out)!=nl) {  // erreur
  469.                           r.statuscode=-1;
  470.                           strcpybuff(r.msg,"Cache Read Error : Read To Disk");
  471.                         }
  472.                       }
  473.                     } while((nl>0) && (size>0) && (r.statuscode!=-1));
  474.                   }
  475.                   
  476.                   fclose(r.out);
  477.                   r.out=NULL;
  478. #if HTS_WIN==0
  479.                   chmod(save,HTS_ACCESS_FILE);      
  480. #endif          
  481.                   //xxusercommand(opt,0,NULL,fconv(save), adr, fil);
  482.                 } else {
  483.                   r.statuscode=-1;
  484.                   strcpybuff(r.msg,"Cache Write Error : Unable to Create File");
  485.                   //printf("%s\n",save);
  486.                 }
  487.               }
  488.               
  489.             } else
  490. #endif
  491.             { // lire en mΘmoire
  492.               
  493.               if (pos<0) {
  494.                 if (strnotempty(save)) { // Pas de donnΘe en cache, bizarre car html!!!
  495.                   r.statuscode=-1;
  496.                   strcpybuff(r.msg,"Previous cache file not found (2)");
  497.                 } else {                 /* Read in memory from cache */
  498.                   if (strnotempty(return_save) && fexist(return_save)) {
  499.                     FILE* fp = fopen(fconv(return_save), "rb");
  500.                     if (fp != NULL) {
  501.                       r.adr=(char*) malloct((INTsys)r.size + 4);
  502.                       if (adr != NULL) {
  503.                         if (r.size > 0 && fread(r.adr, 1, (INTsys) r.size, fp) != r.size) {
  504.                           r.statuscode=-1;
  505.                           strcpybuff(r.msg,"Read error in cache disk data");
  506.                         }
  507.                       } else {
  508.                         r.statuscode=-1;
  509.                         strcpybuff(r.msg,"Read error (memory exhausted) from cache");
  510.                       }
  511.                       fclose(fp);
  512.                     }
  513.                   } else {
  514.                     r.statuscode=-1;
  515.                     strcpybuff(r.msg,"Cache file not found on disk");
  516.                   }
  517.                 }
  518.               } else {
  519.                 // lire fichier (d'un coup)
  520.                 r.adr=(char*) malloct((INTsys)r.size+4);
  521.                 if (r.adr!=NULL) {
  522.                   if (fread(r.adr,1,(INTsys)r.size,cache->olddat)!=r.size) {  // erreur
  523.                     freet(r.adr);
  524.                     r.adr=NULL;
  525.                     r.statuscode=-1;
  526.                     strcpybuff(r.msg,"Cache Read Error : Read Data");
  527.                   } else
  528.                     *(r.adr+r.size)='\0';
  529.                   //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
  530.                 } else {  // erreur
  531.                   r.statuscode=-1;
  532.                   strcpybuff(r.msg,"Cache Memory Error");
  533.                 }
  534.               }
  535.             }
  536.           }    // si save==null, ne rien charger (juste en tΩte)
  537.         } else {
  538. #if DEBUGCA
  539.           printf("Cache Read Error : Bad Data");
  540. #endif
  541.           r.statuscode=-1;
  542.           strcpybuff(r.msg,"Cache Read Error : Bad Data");
  543.         }
  544.       } else {  // erreur
  545. #if DEBUGCA
  546.         printf("Cache Read Error : Read Header");
  547. #endif
  548.         r.statuscode=-1;
  549.         strcpybuff(r.msg,"Cache Read Error : Read Header");
  550.       }
  551.     } else {
  552. #if DEBUGCA
  553.       printf("Cache Read Error : Seek Failed");
  554. #endif
  555.       r.statuscode=-1;
  556.       strcpybuff(r.msg,"Cache Read Error : Seek Failed");
  557.     }
  558.   } else {
  559. #if DEBUGCA
  560.     printf("File Cache Not Found");
  561. #endif
  562.     r.statuscode=-1;
  563.     strcpybuff(r.msg,"File Cache Entry Not Found");
  564.   }
  565.   if (!location) {   /* don't export internal buffer */
  566.     r.location = NULL;
  567.   }
  568.   return r;
  569. }
  570.  
  571. /* write (string1-string2)-data in cache */
  572. /* 0 if failed */
  573. int cache_writedata(FILE* cache_ndx,FILE* cache_dat,char* str1,char* str2,char* outbuff,int len) {
  574.   if (cache_dat) {
  575.     char buff[HTS_URLMAXSIZE*4];
  576.     char s[256];
  577.     int pos;
  578.     fflush(cache_dat); fflush(cache_ndx);
  579.     pos=ftell(cache_dat);
  580.     /* first write data */
  581.     if (cache_wint(cache_dat,len)!=-1) {       // length
  582.       if ((INTsys)fwrite(outbuff,1,(INTsys)len,cache_dat) == (INTsys) len) {   // data
  583.         /* then write index */
  584.         sprintf(s,"%d\n",pos);
  585.         buff[0]='\0'; strcatbuff(buff,str1); strcatbuff(buff,"\n"); strcatbuff(buff,str2); strcatbuff(buff,"\n");
  586.         cache_wstr(cache_ndx,buff);
  587.         if (fwrite(s,1,(INTsys)strlen(s),cache_ndx) == strlen(s)) {
  588.           fflush(cache_dat); fflush(cache_ndx);
  589.           return 1;
  590.         }
  591.       }
  592.     }
  593.   }
  594.   return 0;
  595. }
  596.  
  597. /* read the data corresponding to (string1-string2) in cache */
  598. /* 0 if failed */
  599. int cache_readdata(cache_back* cache,char* str1,char* str2,char** inbuff,int* inlen) {
  600. #if HTS_FAST_CACHE
  601.   if (cache->hashtable) {
  602.     char buff[HTS_URLMAXSIZE*4];
  603.     long int pos;
  604.     strcpybuff(buff,str1); strcatbuff(buff,str2);
  605.     if (inthash_read((inthash)cache->hashtable,buff,(long int*)&pos)) {
  606.       if (fseek(cache->olddat,((pos>0)?pos:(-pos)),SEEK_SET) == 0) {
  607.         INTsys len;
  608.         cache_rint(cache->olddat,&len);
  609.         if (len>0) {
  610.           char* mem_buff=(char*)malloct(len+4);    /* Plus byte 0 */
  611.           if (mem_buff) {
  612.             if ((INTsys)fread(mem_buff,1,len,cache->olddat)==len) { // lire tout (y compris statuscode etc)*/
  613.               *inbuff=mem_buff;
  614.               *inlen=len;
  615.               return 1;
  616.             } else
  617.               freet(mem_buff);
  618.           }
  619.         }
  620.       }
  621.     }
  622.   }
  623. #endif
  624.   *inbuff=NULL;
  625.   *inlen=0;
  626.   return 0;
  627. }
  628.  
  629. // renvoyer uniquement en tΩte, ou NULL si erreur
  630. // return NULL upon error, and set -1 to r.statuscode
  631. htsblk* cache_header(httrackp* opt,cache_back* cache,char* adr,char* fil,htsblk* r) {
  632.   *r=cache_read(opt,cache,adr,fil,NULL,NULL);              // test uniquement
  633.   if (r->statuscode != -1)
  634.     return r;
  635.   else
  636.     return NULL;
  637. }
  638.  
  639.  
  640. // Initialisation du cache: crΘer nouveau, renomer ancien, charger..
  641. void cache_init(cache_back* cache,httrackp* opt) {
  642.   // ---
  643.   // utilisation du cache: renommer ancien Θventuel et charger index
  644.   if (opt->cache) {
  645. #if DEBUGCA
  646.     printf("cache init: ");
  647. #endif
  648.     if (!cache->ro) {
  649. #if HTS_WIN
  650.       mkdir(fconcat(opt->path_log,"hts-cache"));
  651. #else
  652.       mkdir(fconcat(opt->path_log,"hts-cache"),HTS_PROTECT_FOLDER);
  653. #endif
  654.       if ((fexist(fconcat(opt->path_log,"hts-cache/new.dat"))) && (fexist(fconcat(opt->path_log,"hts-cache/new.ndx")))) {  // il existe dΘja un cache prΘcΘdent.. renommer
  655. #if DEBUGCA
  656.         printf("work with former cache\n");
  657. #endif
  658.         if (fexist(fconcat(opt->path_log,"hts-cache/old.dat")))
  659.           remove(fconcat(opt->path_log,"hts-cache/old.dat"));
  660.         if (fexist(fconcat(opt->path_log,"hts-cache/old.ndx")))
  661.           remove(fconcat(opt->path_log,"hts-cache/old.ndx"));
  662.         
  663.         rename(fconcat(opt->path_log,"hts-cache/new.dat"),fconcat(opt->path_log,"hts-cache/old.dat"));
  664.         rename(fconcat(opt->path_log,"hts-cache/new.ndx"),fconcat(opt->path_log,"hts-cache/old.ndx"));
  665.       } else {  // un des deux (ou les deux) fichiers cache absents: effacer l'autre Θventuel
  666. #if DEBUGCA
  667.         printf("new cache\n");
  668. #endif
  669.         if (fexist(fconcat(opt->path_log,"hts-cache/new.dat")))
  670.           remove(fconcat(opt->path_log,"hts-cache/new.dat"));
  671.         if (fexist(fconcat(opt->path_log,"hts-cache/new.ndx")))
  672.           remove(fconcat(opt->path_log,"hts-cache/new.ndx"));
  673.       }
  674.     }
  675.     
  676.     // charger index cache prΘcΘdent
  677.     if (
  678.       (
  679.       !cache->ro &&
  680.       fsize(fconcat(opt->path_log,"hts-cache/old.dat")) >=0 && fsize(fconcat(opt->path_log,"hts-cache/old.ndx")) >0
  681.       )
  682.       ||
  683.       (
  684.       cache->ro &&
  685.       fsize(fconcat(opt->path_log,"hts-cache/new.dat")) >=0 && fsize(fconcat(opt->path_log,"hts-cache/new.ndx")) > 0
  686.       )
  687.       ) {
  688.       FILE* oldndx=NULL;
  689. #if DEBUGCA
  690.       printf("..load cache\n");
  691. #endif
  692.       if (!cache->ro) {
  693.         cache->olddat=fopen(fconcat(opt->path_log,"hts-cache/old.dat"),"rb");        
  694.         oldndx=fopen(fconcat(opt->path_log,"hts-cache/old.ndx"),"rb");        
  695.       } else {
  696.         cache->olddat=fopen(fconcat(opt->path_log,"hts-cache/new.dat"),"rb");        
  697.         oldndx=fopen(fconcat(opt->path_log,"hts-cache/new.ndx"),"rb");        
  698.       }
  699.       // les deux doivent Ωtre ouvrables
  700.       if ((cache->olddat==NULL) && (oldndx!=NULL)) {
  701.         fclose(oldndx);
  702.         oldndx=NULL;
  703.       }
  704.       if ((cache->olddat!=NULL) && (oldndx==NULL)) {
  705.         fclose(cache->olddat);
  706.         cache->olddat=NULL;
  707.       }
  708.       // lire index
  709.       if (oldndx!=NULL) {
  710.         int buffl;
  711.         fclose(oldndx); oldndx=NULL;
  712.         // lire ndx, et lastmodified
  713.         if (!cache->ro) {
  714.           buffl=fsize(fconcat(opt->path_log,"hts-cache/old.ndx"));
  715.           cache->use=readfile(fconcat(opt->path_log,"hts-cache/old.ndx"));
  716.         } else {
  717.           buffl=fsize(fconcat(opt->path_log,"hts-cache/new.ndx"));
  718.           cache->use=readfile(fconcat(opt->path_log,"hts-cache/new.ndx"));
  719.         }
  720.         if (cache->use!=NULL) {
  721.           char firstline[256];
  722.           char* a=cache->use;
  723.           a+=cache_brstr(a,firstline);
  724.           if (strncmp(firstline,"CACHE-",6)==0) {       // Nouvelle version du cache
  725.             if (strncmp(firstline,"CACHE-1.",8)==0) {      // Version 1.1x
  726.               cache->version=(int)(firstline[8]-'0');           // cache 1.x
  727.               if (cache->version <= 4) {
  728.                 a+=cache_brstr(a,firstline);
  729.                 strcpybuff(cache->lastmodified,firstline);
  730.               } else {
  731.                 if (opt->errlog) {
  732.                   fspc(opt->errlog,"error"); fprintf(opt->errlog,"Cache: version 1.%d not supported, ignoring current cache"LF,cache->version);
  733.                   fflush(opt->errlog);
  734.                 }
  735.                 fclose(cache->olddat);
  736.                 cache->olddat=NULL;
  737.                 freet(cache->use);
  738.                 cache->use=NULL;
  739.               }
  740.             } else {        // non supportΘ
  741.               if (opt->errlog) {
  742.                 fspc(opt->errlog,"error"); fprintf(opt->errlog,"Cache: %s not supported, ignoring current cache"LF,firstline);
  743.                 fflush(opt->errlog);
  744.               }
  745.               fclose(cache->olddat);
  746.               cache->olddat=NULL;
  747.               freet(cache->use);
  748.               cache->use=NULL;
  749.             }
  750.             /* */
  751.           } else {              // Vieille version du cache
  752.             /* */
  753.             if (opt->log) {
  754.               fspc(opt->log,"warning"); fprintf(opt->log,"Cache: importing old cache format"LF);
  755.               fflush(opt->log);
  756.             }
  757.             cache->version=0;        // cache 1.0
  758.             strcpybuff(cache->lastmodified,firstline); 
  759.           }
  760.           opt->is_update=1;        // signaler comme update
  761.           
  762.           /* Create hash table for the cache (MUCH FASTER!) */
  763. #if HTS_FAST_CACHE
  764.           if (cache->use) {
  765.             char line[HTS_URLMAXSIZE*2];
  766.             char linepos[256];
  767.             int  pos;
  768.             while ( (a!=NULL) && (a < (cache->use+buffl) ) ) {
  769.               a=strchr(a+1,'\n');     /* start of line */
  770.               if (a) {
  771.                 a++;
  772.                 /* read "host/file" */
  773.                 a+=binput(a,line,HTS_URLMAXSIZE);
  774.                 a+=binput(a,line+strlen(line),HTS_URLMAXSIZE);
  775.                 /* read position */
  776.                 a+=binput(a,linepos,200);
  777.                 sscanf(linepos,"%d",&pos);
  778.                 inthash_add((inthash)cache->hashtable,line,pos);
  779.               }
  780.             }
  781.             /* Not needed anymore! */
  782.             freet(cache->use);
  783.             cache->use=NULL;
  784.           }
  785. #endif
  786.         }
  787.       }
  788.       }  // taille cache>0
  789.       
  790. #if DEBUGCA
  791.       printf("..create cache\n");
  792. #endif
  793.       if (!cache->ro) {
  794.         // ouvrir caches actuels
  795.         structcheck(fconcat(opt->path_log, "hts-cache/"));
  796.         cache->dat=fopen(fconcat(opt->path_log,"hts-cache/new.dat"),"wb");        
  797.         cache->ndx=fopen(fconcat(opt->path_log,"hts-cache/new.ndx"),"wb");        
  798.         // les deux doivent Ωtre ouvrables
  799.         if ((cache->dat==NULL) && (cache->ndx!=NULL)) {
  800.           fclose(cache->ndx);
  801.           cache->ndx=NULL;
  802.         }
  803.         if ((cache->dat!=NULL) && (cache->ndx==NULL)) {
  804.           fclose(cache->dat);
  805.           cache->dat=NULL;
  806.         }
  807.         
  808.         if (cache->ndx!=NULL) {
  809.           char s[256];
  810.           
  811.           cache_wstr(cache->dat,"CACHE-1.4");
  812.           fflush(cache->dat);
  813.           cache_wstr(cache->ndx,"CACHE-1.4");
  814.           fflush(cache->ndx);
  815.           //
  816.           time_gmt_rfc822(s);   // date et heure actuelle GMT pour If-Modified-Since..
  817.           cache_wstr(cache->ndx,s);        
  818.           fflush(cache->ndx);    // un petit fflush au cas o∙
  819.           
  820.           // supprimer old.lst
  821.           if (fexist(fconcat(opt->path_log,"hts-cache/old.lst")))
  822.             remove(fconcat(opt->path_log,"hts-cache/old.lst"));
  823.           // renommer
  824.           if (fexist(fconcat(opt->path_log,"hts-cache/new.lst")))
  825.             rename(fconcat(opt->path_log,"hts-cache/new.lst"),fconcat(opt->path_log,"hts-cache/old.lst"));
  826.           // ouvrir
  827.           cache->lst=fopen(fconcat(opt->path_log,"hts-cache/new.lst"),"wb");
  828.           {
  829.             filecreate_params tmp;
  830.             strcpybuff(tmp.path,opt->path_html);    // chemin
  831.             tmp.lst=cache->lst;                 // fichier lst
  832.             filenote("",&tmp);        // initialiser filecreate
  833.           }
  834.           
  835.           // supprimer old.txt
  836.           if (fexist(fconcat(opt->path_log,"hts-cache/old.txt")))
  837.             remove(fconcat(opt->path_log,"hts-cache/old.txt"));
  838.           // renommer
  839.           if (fexist(fconcat(opt->path_log,"hts-cache/new.txt")))
  840.             rename(fconcat(opt->path_log,"hts-cache/new.txt"),fconcat(opt->path_log,"hts-cache/old.txt"));
  841.           // ouvrir
  842.           cache->txt=fopen(fconcat(opt->path_log,"hts-cache/new.txt"),"wb");
  843.           if (cache->txt) {
  844.             fprintf(cache->txt,"date\tsize'/'remotesize\tflags(request:Update,Range state:File response:Modified,Chunked,gZipped)\t");
  845.             fprintf(cache->txt,"statuscode\tstatus ('servermsg')\tMIME\tEtag|Date\tURL\tlocalfile\t(from URL)"LF);
  846.           }
  847.           
  848.           // test
  849.           // cache_writedata(cache->ndx,cache->dat,"//[TEST]//","test1","TEST PIPO",9);
  850.         }
  851.         
  852.       } else {
  853.         cache->lst = cache->dat = cache->ndx = NULL;
  854.       }
  855.       
  856.   }
  857.   
  858. }
  859.  
  860.  
  861.  
  862.  
  863. // lire un fichier.. (compatible \0)
  864. char* readfile(char* fil) {
  865.   char* adr=NULL;
  866.   INTsys len=0;
  867.   len=fsize(fil);
  868.   if (len >= 0) {  // exists
  869.     FILE* fp;
  870.     fp=fopen(fconv(fil),"rb");
  871.     if (fp!=NULL) {  // n'existe pas (!)
  872.       adr=(char*) malloct(len+1);
  873.       if (adr!=NULL) {
  874.         if (len > 0 && (INTsys)fread(adr,1,len,fp) != len) {    // fichier endommagΘ ?
  875.           freet(adr);
  876.           adr=NULL;
  877.         } else
  878.           *(adr+len)='\0';
  879.       }
  880.       fclose(fp);
  881.     }
  882.   }
  883.   return adr;
  884. }
  885.  
  886. char* readfile_or(char* fil,char* defaultdata) {
  887.   char* realfile=fil;
  888.   char* ret;
  889.   if (!fexist(fil))
  890.     realfile=fconcat(hts_rootdir(NULL),fil);
  891.   ret=readfile(realfile);
  892.   if (ret)
  893.     return ret;
  894.   else {
  895.     char *adr=malloct(strlen(defaultdata)+2);
  896.     if (adr) {
  897.       strcpybuff(adr,defaultdata);
  898.       return adr;
  899.     }
  900.   }
  901.   return NULL;
  902. }
  903.  
  904. // Θcriture/lecture d'une chaεne sur un fichier
  905. // -1 : erreur, sinon 0
  906. int cache_wstr(FILE* fp,char* s) {
  907.   INTsys i;
  908.   char buff[256+4];
  909.   i=strlen(s);
  910.   sprintf(buff,INTsysP "\n",i);
  911.   if (fwrite(buff,1,(INTsys)strlen(buff),fp) != strlen(buff))
  912.     return -1;
  913.   if (i>0)
  914.   if ((INTsys)fwrite(s,1,i,fp) != i)
  915.     return -1;
  916.   return 0;
  917. }
  918. void cache_rstr(FILE* fp,char* s) {
  919.   INTsys i;
  920.   char buff[256+4];
  921.   linput(fp,buff,256);
  922.   sscanf(buff,INTsysP,&i);
  923.   if (i < 0 || i > 32768)    /* error, something nasty happened */
  924.     i=0;
  925.   if (i>0)
  926.     fread(s,1,i,fp);
  927.   *(s+i)='\0';
  928. }
  929. int cache_brstr(char* adr,char* s) {
  930.   int i;
  931.   int off;
  932.   char buff[256+4];
  933.   off=binput(adr,buff,256);
  934.   adr+=off;
  935.   sscanf(buff,"%d",&i);
  936.   if (i>0)
  937.     strncpy(s,adr,i);
  938.   *(s+i)='\0';
  939.   off+=i;
  940.   return off;
  941. }
  942. int cache_quickbrstr(char* adr,char* s) {
  943.   int i;
  944.   int off;
  945.   char buff[256+4];
  946.   off=binput(adr,buff,256);
  947.   adr+=off;
  948.   sscanf(buff,"%d",&i);
  949.   if (i>0)
  950.     strncpy(s,adr,i);
  951.   *(s+i)='\0';
  952.   off+=i;
  953.   return off;
  954. }
  955. /* idem, mais en int */
  956. int cache_brint(char* adr,int* i) {
  957.   char s[256];
  958.   int r=cache_brstr(adr,s);
  959.   if (r!=-1)
  960.     sscanf(s,"%d",i);
  961.   return r;
  962. }
  963. void cache_rint(FILE* fp,int* i) {
  964.   char s[256];
  965.   cache_rstr(fp,s);
  966.   sscanf(s,"%d",i);
  967. }
  968. int cache_wint(FILE* fp,int i) {
  969.   char s[256];
  970.   sprintf(s,"%d",(int) i);
  971.   return cache_wstr(fp,s);
  972. }
  973. void cache_rLLint(FILE* fp,LLint* i) {
  974.   char s[256];
  975.   cache_rstr(fp,s);
  976.   sscanf(s,LLintP,i);
  977. }
  978. int cache_wLLint(FILE* fp,LLint i) {
  979.   char s[256];
  980.   sprintf(s,LLintP,(LLint) i);
  981.   return cache_wstr(fp,s);
  982. }
  983. // -- cache --
  984.